#include "WiFi.h"
#include "SPIFFS.h"
#include <ESPmDNS.h>
#include <WebServer.h>
#include <WiFiMulti.h>
#include "ESPAsyncWebServer.h"
#include <WebSocketsServer.h>
#include <Adafruit_NeoPixel.h>
#include <ArduinoJson.h>


// wifi设置 两种模式
// wifiAP模式设置
const char* AP_SSID  = "ESP32_Config"; //热点名称
const char* AP_PASS  = "12345678";  //密码

// 普通配网设置
const char* WIFI_SSID  = "sx406"; //热点名称 自行修改
const char* WIFI_PASS  = "lihongchen0531";  //密码 自行修改

WebServer server(80);
WiFiMulti wifiMulti;

// 16个颜色的RGB数值
const char *colorList[16] = {"000000000", "029043083", "126037083", "000135081", 
					"171082054", "095087079", "194195199", "255241232", 
					"255000077", "255163000", "255255039", "000231086", 
					"041173255", "131118156", "255119168", "255204170"};


void handleUserRequet();
bool handleFileRead(String path);
String getContentType(String filename);
void changeLED();
int HexToDec(char x);

// 配置ws2812 64个灯珠 dataIn连接esp主控的IO4
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(64, 4, NEO_GRB + NEO_KHZ400);


void setup(){
	// 先冷静3秒
	delay(3000);

	// 初始化ws2812
	pixels.begin();
	pixels.fill(pixels.Color(0, 0, 0)); 
	pixels.show();
	Serial.begin(115200);

	// 若使用wifiAP模式请取消注释以下代码
	// WiFi.mode(WIFI_AP);//配置为AP模式

	// 若使用wifiAP模式请 **注释** 以下代码
	WiFi.begin(WIFI_SSID, WIFI_PASS);

	// 启动闪存文件系统
	if(SPIFFS.begin()){                     
		Serial.println("SPIFFS Started.");
	} else {
		Serial.println("SPIFFS Failed to Start.");
	}

	// 若使用wifiAP模式请取消注释以下代码
	// //开启WIFI AP
	// boolean result = WiFi.softAP(AP_SSID, AP_PASS);
	// if (result){
	// 	IPAddress myIP = WiFi.softAPIP();
	// 	//打印相关信息
	// 	Serial.println("");
	// 	Serial.print("Soft-AP IP address = ");
	// 	Serial.println(myIP);
	// 	Serial.println(String("MAC address = ")  + WiFi.softAPmacAddress().c_str());
	// 	Serial.println("waiting ...");
    // } else {  //开启热点失败
	// 	Serial.println("WiFiAP Failed");
	// 	delay(3000);
	// 	ESP.restart();  //复位esp32
    // }
	
	// 开启MDNS服务 可以通过访问 http://esp32.local/ 获取index.html
	if (MDNS.begin("esp32")) {
		Serial.println("MDNS responder started");
    }

	server.onNotFound(handleUserRequet);      // 告知系统如何处理用户请求
	server.on("/changeLED", changeLED);
	server.begin();
}
 
void loop(){
	server.handleClient();                    // 处理用户请求
}


// 处理用户浏览器的HTTP访问
void handleUserRequet() {         
	// 获取用户请求网址信息
	String webAddress = server.uri();
	// 通过handleFileRead函数处处理用户访问
	bool fileReadOK = handleFileRead(webAddress);
	// 如果在SPIFFS无法找到用户访问的资源，则回复404 (Not Found)
	if (!fileReadOK){                                                 
		server.send(404, "text/plain", "404 Not Found"); 
	}
}

//处理浏览器HTTP访问
bool handleFileRead(String path) {    
	if (path.endsWith("/")) {                   // 如果访问地址以"/"为结尾
		path = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
	} 
	Serial.println(path);
	String contentType = getContentType(path);  // 获取文件类型
	if (SPIFFS.exists(path)) {                     // 如果访问的文件可以在SPIFFS中找到
		File file = SPIFFS.open(path, "r");          // 则尝试打开该文件
		server.streamFile(file, contentType);// 并且将该文件返回给浏览器
		file.close();                                // 并且关闭文件
		return true;                                 // 返回true
	}
	return false;                                  // 如果文件未找到，则返回false
}

// 获取文件类型
String getContentType(String filename){
	if(filename.endsWith(".htm")) return "text/html";
	else if(filename.endsWith(".html")) return "text/html";
	else if(filename.endsWith(".css")) return "text/css";
	else if(filename.endsWith(".js")) return "application/javascript";
	else if(filename.endsWith(".png")) return "image/png";
	else if(filename.endsWith(".gif")) return "image/gif";
	else if(filename.endsWith(".jpg")) return "image/jpeg";
	else if(filename.endsWith(".ico")) return "image/x-icon";
	else if(filename.endsWith(".xml")) return "text/xml";
	else if(filename.endsWith(".pdf")) return "application/x-pdf";
	else if(filename.endsWith(".zip")) return "application/x-zip";
	else if(filename.endsWith(".gz")) return "application/x-gzip";
	else if(filename.endsWith(".json")) return "application/json";
	return "text/plain";
}

// 接收浏览器返回的表情信息；并控制灯带显示
void changeLED(){
	String LEDmess = server.arg("LEDmess");
	for (int i = 0; i < 64; i ++){
		int colorIndex = HexToDec(LEDmess.charAt(i));
		String RGBstring = colorList[colorIndex];
		int R = RGBstring.substring(0,3).toInt();
		int G = RGBstring.substring(3,6).toInt();
		int B = RGBstring.substring(6,9).toInt();
		int flag = (i+1)/8;
		int Remainder = (i+1)%8;
		if (flag % 2 == 0 && Remainder != 0){
			pixels.setPixelColor(i, pixels.Color(R, G, B));
			Serial.println(i);
		}else if(flag % 2 == 1 && Remainder == 0){
			pixels.setPixelColor(i, pixels.Color(R, G, B));
			Serial.println(i);
		}else if(flag % 2 == 0 && Remainder == 0){
			pixels.setPixelColor(8*(flag-1), pixels.Color(R, G, B));
			Serial.println(8*(flag-1));
		}else{
			pixels.setPixelColor(8*flag+8-Remainder, pixels.Color(R, G, B));
			Serial.println(8*flag+8-Remainder);
		}

	}
	pixels.setBrightness(2);
	pixels.show();
	server.send(200, "text/plain", LEDmess);
}

// 十六进制字符转十进制int
int HexToDec(char x){	
	if (x == 'a') {return 10;}
	else if (x == 'b') {return 11;}
	else if (x == 'c') {return 12;}
	else if (x == 'd') {return 13;}
	else if (x == 'e') {return 14;}
	else if (x == 'f') {return 15;}
	else if (x == '0') {return 0;}
	else if (x == '1') {return 1;}
	else if (x == '2') {return 2;}
	else if (x == '3') {return 3;}
	else if (x == '4') {return 4;}
	else if (x == '5') {return 5;}
	else if (x == '6') {return 6;}
	else if (x == '7') {return 7;}
	else if (x == '8') {return 8;}
	else if (x == '9') {return 9;}
	else return (int) x;
	return 0;
}